#include "FileSystem.h"

#define PATH_MAX_LEN				1000

#include "Config.h"

#ifdef __COMPILE_WIN32__
#include <io.h>
#include <windows.h>
#include <direct.h>
#endif
#include "include/ILog.h"

#include "IOFileDisk.h"
#include "IOPFSFileDisk.h"
#include "IOPFSFileAttached.h"

CFileSystem::CFileSystem():AutomaticLoading(false),WorkingDirectory(""),Base(NULL),ActualAttachedReading(0)
{
	SetWorkingDirectoryToStartDirectory();
	pLogRelease << "FileSystem class created..." << endl;
}

CFileSystem::~CFileSystem()
{
	for (std::vector<FileSearchingStrc*>::iterator it=FileSearching.begin();it!=FileSearching.end();it++)
	{
		FileSearchingStrc *Temp = (*it);
		DEALLOCATE(Temp);
	}

	for (std::vector<PFSFilePointer*>::iterator it=fpvec.begin();it!=fpvec.end();it++)
	{
		PFSFilePointer *Temp = (*it);
		DEALLOCATE(Temp);
	}

	for (std::vector<AttachedFileSystemsStrc*>::iterator it=AttachedFileSystems.begin();it!=AttachedFileSystems.end();it++)
	{
		AttachedFileSystemsStrc *Temp = (*it);
		DEALLOCATE(Temp);
	}

	DEALLOCATE(Base);
}

bool CFileSystem::SetWorkingDirectoryToStartDirectory()
{
#ifdef __COMPILE_WIN32__
	char Temp[PATH_MAX_LEN];
	_getcwd(Temp,PATH_MAX_LEN);
	WorkingDirectory = Temp;
	WorkingDirectory += "\\";
#else
	WorkingDirectory = "./";
#endif
	pLogDebug << "CFileSystem: Working directory is: " << WorkingDirectory << endl;
	return true;
}

bool CFileSystem::ReadActualDirectory()
{
	if (!Base)
	{
		Base = GetNewCIOFile(WorkingDirectory,"");
		Base->fd.IsDirectory = true;
		Base->CreateChildTree();
		return true;
	}
	return false;
}

stringc CFileSystem::GetWorkingDirectory()
{
	return WorkingDirectory;
}

IImage *CFileSystem::GetImage(stringc Name)
{
	return GetLoadedImage(Name);
}

CLoadedImage *CFileSystem::GetLoadedImage(stringc Name)
{
	CIOFile *Image = Base->Search(Name);

	if (Image)
	{
		if (!(Image->fd.IsLoaded))
		{
				Image->LoadEntireFile();
		}

		CLoadedImage *Ret = fl.ImageLoad((u32*)Image->GetBuffer(),Image->fd.Size);
		return Ret;
	}

	return NULL;
}

IIOFile *CFileSystem::GetFile(stringc Name)
{
	if (Name=="")
		return GetBaseFile();

	return Base->Search(Name);
}

IIOFile *CFileSystem::GetBaseFile()
{
	return Base;
}

CIOFile *CFileSystem::GetNewCIOFile(stringc Dir,stringc File)
{
	if (ActualAttachedReading < AttachedFileSystems.size())
		return new CIOPFSFileAttached(Dir,File,this);

	stringc Completefn = Dir + File;
	if (Completefn.size()>3)
	{
		for (u32 i=0;i<Completefn.size()-3;i++)
		{
			stringc DirTemp = Completefn.substr(i,4);
			if (DirTemp == PFS_FILEONDISK_EXT)
			{
				return new CIOPFSFileDisk(Dir,File,this);
			}
			else if (DirTemp == PFS_FILEONMEM_EXT)
			{
				return new CIOPFSFileAttached(Dir,File,this);
			}
		}
	}

	return new CIOFileDisk(Dir,File,this);
}

bool CFileSystem::ReadAttachedFileSystem(u8 *Data,stringc FileName)
{
	if (Data)
	{
		AttachedFileSystemsStrc *Temp = new AttachedFileSystemsStrc;
		Temp->Readed = false;
		Temp->Data = Data;
		Temp->PFSFileName = WorkingDirectory + FileName;
		Temp->FilePointer = 0;
		AttachedFileSystems.push_back(Temp);

		CIOPFSFileAttached *File = new CIOPFSFileAttached(WorkingDirectory,FileName,this);
		File->CreateChildTree();
		IncActualAttachedReading();
		Base->AddChild(File);
		return true;
	}

	return false;
}

std::vector<AttachedFileSystemsStrc*> &CFileSystem::GetAttachedFileSystems()
{
	return AttachedFileSystems;
}

void CFileSystem::IncActualAttachedReading()
{
	ActualAttachedReading++;
}

std::vector<FileSearchingStrc*> & CFileSystem::GetFileSearching()
{
	return FileSearching;
}
